home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / rayshade / libshade / shade.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  10KB  |  377 lines

  1. /*
  2.  * shade.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * $Id: shade.c,v 4.0 91/07/17 14:47:36 kolb Exp Locker: kolb $
  17.  *
  18.  * $Log:    shade.c,v $
  19.  * Revision 4.0  91/07/17  14:47:36  kolb
  20.  * Initial version.
  21.  * 
  22.  */
  23. #include "rayshade.h"
  24. #include "libtext/texture.h"
  25. #include "libsurf/surface.h"
  26. #include "liblight/light.h"
  27. #include "libsurf/atmosphere.h"
  28. #include "options.h"
  29. #include "stats.h"
  30.  
  31. Medium    TopMedium;
  32. Atmosphere *AtmosEffects;
  33.  
  34. static void shade(), LightRay(), Lighting(), ReflectRay();
  35. static int TransmitRay();
  36.  
  37. /*
  38.  * Calculate color of ray.
  39.  */
  40. void
  41. ShadeRay(hitlist, ray, dist, back, color, contrib)
  42. HitList *hitlist;        /* Information about point of intersection. */
  43. Ray *ray;            /* Direction and origin of ray. */
  44. Float dist;            /* Distance from origin of intersection. */
  45. Color    *back,            /* "Background" color */
  46.     *color,            /* Color to assign current ray. */
  47.     *contrib;        /* Contribution of this ray to final color */
  48. {
  49.     Vector norm, gnorm, pos; /* surface normal, point of intersection */
  50.     Surface surf, *stmp;    /* surface properties */
  51.     int enter, smooth;    /* entering ?, gnorm != snorm ?*/
  52.  
  53.     if (hitlist->nodes == 0) {
  54.         /*
  55.          * No valid intersection.  Set distance for atmospheric
  56.          * effects and set color of ray to background.
  57.          */
  58.         *color = *back;
  59.         VecAddScaled(ray->pos, FAR_AWAY, ray->dir, &pos);
  60.         if (!ray->media && AtmosEffects)
  61.             Atmospherics(AtmosEffects, ray, FAR_AWAY, &pos, color);
  62.         return;
  63.     }
  64.  
  65.     /*
  66.      * Compute normal, surface properties, etc.
  67.      */
  68.     stmp = GetShadingSurf(hitlist);
  69.     surf = *stmp;
  70.     enter = ComputeSurfProps(hitlist, ray, &pos, &norm, &gnorm, &surf,
  71.             &smooth);
  72.     Stats.HitRays++;
  73.  
  74.     /*
  75.      * Calculate ray color.
  76.      */
  77.     shade(&pos, ray, &norm, &gnorm, smooth, enter, &surf, back, color,
  78.             contrib);
  79.     if (!ray->media && AtmosEffects)
  80.         Atmospherics(AtmosEffects, ray, dist, &pos, color);
  81. }
  82.  
  83. /*
  84.  * Perform lighting calculations based on surface normal & other properties,
  85.  * incident ray direction and position, and light source properties.
  86.  * Spawn any necessary reflected and transmitted rays.
  87.  */
  88. static void
  89. shade(pos, ray, nrm, gnrm, smooth, enter, surf, back, color, contrib)
  90. Vector *pos, *nrm, *gnrm;    /* hit pos, shade normal, geo normal */
  91. int smooth;            /* true if shading norm and geo norm differ */
  92. int enter;            /* TRUE if entering surface */
  93. Ray *ray;            /* indicent ray */
  94. Surface *surf;            /* properties of hit surface */
  95. Color *back, *color;        /* background color, computed color */
  96. Color *contrib;            /* contribution to final pixel value */
  97. {
  98.     Float    k;        /* -ray . normal */
  99.     Color    newcontrib;
  100.     Vector    refl;        /* reflected direction */
  101.     Color    reflectivity,    /* effective surface reflectivity */
  102.         intens;        /* reflected/transmitted intensity */
  103.     Light *lp;        /* current light source */
  104.     extern Light *Lights;    /* list of defined sources */
  105.  
  106.     /*
  107.      * Ambient color is always included.
  108.      */
  109.     ColorMultiply(surf->amb, Options.ambient, color);
  110.  
  111.     /*
  112.      * Calculate direction of reflected ray.
  113.      */
  114.     k = -dotp(&ray->dir, nrm);
  115.     VecAddScaled(ray->dir, 2.*k, *nrm, &refl);
  116.  
  117.     /*
  118.      * Calculate intensity contributed by each light source.
  119.      */
  120.     for (lp = Lights; lp; lp = lp->next)
  121.         LightRay(lp, pos, nrm, gnrm, smooth, &refl, surf,
  122.                 ray->depth, ray->sample, ray->time, color);
  123.  
  124.     if (ray->depth >= Options.maxdepth)
  125.         /*
  126.          * Don't spawn any transmitted/reflected rays.
  127.          */
  128.         return;
  129.     /*
  130.      * Specular transmission (refraction).
  131.      */
  132.     ColorScale(surf->reflect, surf->spec, &reflectivity);
  133.  
  134.     if (surf->transp > EPSILON) {
  135.         ColorScale(surf->transp, surf->body, &intens);
  136.         ColorMultiply(intens, *contrib, &newcontrib);
  137.         if (newcontrib.r > Options.cutoff.r ||
  138.             newcontrib.g > Options.cutoff.g ||
  139.             newcontrib.b > Options.cutoff.b)
  140.             /*
  141.              * Transmit ray.  If TIR occurs, add transmitted
  142.              * component to reflected component.  Kinda strange, but...
  143.              */
  144.             if (TransmitRay(ray, pos, nrm, k, surf->index,
  145.                 surf->statten, enter, back, &newcontrib, &intens, color))
  146.                 ColorAdd(reflectivity, intens, &reflectivity);
  147.     }
  148.  
  149.     if (reflectivity.r > EPSILON ||
  150.         reflectivity.g > EPSILON ||
  151.         reflectivity.b > EPSILON) {
  152.         ColorMultiply(reflectivity, *contrib, &newcontrib);
  153.         if (newcontrib.r > Options.cutoff.r ||
  154.             newcontrib.g > Options.cutoff.g ||
  155.             newcontrib.b > Options.cutoff.b)
  156.             ReflectRay(ray, pos, &refl, back, &reflectivity,
  157.                 &newcontrib, color);
  158.     }
  159. }
  160.  
  161. /*
  162.  * Lighting calculations
  163.  */
  164. static void
  165. LightRay(lp, pos, norm, gnorm, smooth, reflect, surf, depth, samp, time, color)
  166. Light *lp;            /* Light source */
  167. Vector *pos, *norm, *gnorm;    /* hit pos, shade norm, geo norm */
  168. int smooth;            /* true if shade and geo norm differ */
  169. Vector *reflect;        /* reflection direction */
  170. Surface *surf;            /* surface characteristics */
  171. int depth, samp;        /* ray depth, sample # */
  172. Float time;
  173. Color *color;            /* resulting color */
  174. {
  175.     Color lcolor;
  176.     Ray newray;
  177.     Float costheta, cosalpha, dist;
  178.  
  179.     newray.pos = *pos;
  180.     newray.depth = depth;
  181.     newray.sample = samp;
  182.     newray.time = time; 
  183.     newray.media = (Medium *)NULL;    
  184.  
  185.     LightDirection(lp, pos, &newray.dir, &dist);
  186.  
  187.     costheta = dotp(&newray.dir, norm);
  188.  
  189.     if (smooth) {
  190.         cosalpha = dotp(&newray.dir, gnorm); 
  191.         /*
  192.          * If shading normal indicates self-shadowing
  193.          * and geom normal indicates no self-shadowing,
  194.          * trust the geom normal.
  195.          */
  196.         if (costheta <= 0. && cosalpha > 0.)
  197.             costheta = cosalpha;
  198.         /*
  199.          * If geom normal indicates self-shadowing and
  200.          * geom normal doesn't, then have to do something
  201.          * clever ala Snyder & Barr.
  202.          */
  203.     }
  204.  
  205.     if (costheta <= 0.) {
  206.         /*
  207.          * Light source is on opposite side of surface,
  208.          * hence light must be transmitted through...
  209.          */
  210.         if (surf->translucency < EPSILON)
  211.             return;
  212.         if (!LightIntens(lp, &newray, dist,
  213.             (int)surf->noshadow, &lcolor))
  214.             return;
  215.         cosalpha = -dotp(reflect, &newray.dir);
  216.         Lighting(-costheta, cosalpha, &lcolor, &surf->translu,
  217.                 &surf->body, surf->stexp, color);
  218.         ColorScale(surf->translucency, *color, color);
  219.     } else {
  220.         if (!LightIntens(lp, &newray, dist,
  221.             (int)surf->noshadow, &lcolor))
  222.             return;  /* prim is in shadow w.r.t light source */
  223.  
  224.         cosalpha = dotp(reflect, &newray.dir);
  225.         Lighting(costheta, cosalpha, &lcolor, &surf->diff,
  226.                 &surf->spec, surf->srexp, color);
  227.     }
  228. }
  229.  
  230. /*
  231.  * Compute shading function (diffuse reflection and specular highlight)
  232.  *
  233.  * This function *adds* the computed color to "color".
  234.  */
  235. static void
  236. Lighting(costheta, cosalpha, lcolor, diff, spec, coef, color)
  237. Float costheta, cosalpha, coef;
  238. Color *diff, *spec, *color, *lcolor;
  239. {
  240.     Float intens;
  241.  
  242.     /*
  243.      * Diffuse reflection.
  244.      * Falls off as the cosine of the angle between
  245.      * the normal and the ray to the light (costheta).
  246.      */
  247.     color->r += diff->r * costheta * lcolor->r;
  248.     color->g += diff->g * costheta * lcolor->g;
  249.     color->b += diff->b * costheta * lcolor->b;
  250.     /*
  251.      * Specularly reflected highlights.
  252.      * Fall off as the cosine of the angle
  253.      * between the reflected ray and the ray to the light source.
  254.      */
  255.     if (coef < EPSILON || cosalpha <= 0.)
  256.         return;
  257.     /*
  258.      * Specular highlight = cosine of the angle raised to the
  259.      * appropriate power.
  260.      */
  261.     intens = pow(cosalpha, coef);
  262.     color->r += spec->r * intens * lcolor->r;
  263.     color->g += spec->g * intens * lcolor->g;
  264.     color->b += spec->b * intens * lcolor->b;
  265. }
  266.  
  267. /*
  268.  * Spawn a transmitted ray.  Returns TRUE if total internal reflection
  269.  * occurs, FALSE otherwise.
  270.  */
  271. static int
  272. TransmitRay(ray, pos, norm, k, index, statten, enter, back, contrib, intens, color)
  273. Ray *ray;
  274. Vector *pos, *norm;
  275. Float k, index, statten;
  276. int enter;
  277. Color *back, *contrib, *intens, *color;
  278. {
  279.     int total_int_refl = FALSE;
  280.     Ray NewRay;
  281.     Float dist;
  282.     Color newcol;
  283.     HitList hittmp;        /* Geom intersection record */
  284.  
  285.     NewRay.pos = *pos;        /* Origin == hit point */
  286.     NewRay.media = ray->media;    /* Media == old media */
  287.     NewRay.sample = ray->sample;
  288.     NewRay.time = ray->time;
  289.     NewRay.depth = ray->depth + 1;
  290.  
  291.     if (enter) {
  292.         /*
  293.          * Entering surface.
  294.          */
  295.         if (Refract(&NewRay.dir,
  296.             NewRay.media ? NewRay.media->index :
  297.             TopMedium.index, index, &ray->dir, norm, k)) {
  298.             total_int_refl = TRUE;
  299.         } else {
  300.             /*
  301.              * Push information for new medium.
  302.              */
  303.             NewRay.media = MediumPush(index, statten, NewRay.media);
  304.         }
  305.     } else {
  306.         /*
  307.          * Exiting surface
  308.          * Pop medium from stack.
  309.          */
  310.         if (NewRay.media != (Medium *)0)
  311.             NewRay.media = NewRay.media->next;
  312.         if (Refract(&NewRay.dir, index,
  313.             NewRay.media ? NewRay.media->index :
  314.             TopMedium.index, &ray->dir, norm, k)) {
  315.             total_int_refl = TRUE;
  316.         }
  317.     }
  318.  
  319.     /*
  320.      * At this point, NewRay.media is the medium into which
  321.      * the new ray is entering.
  322.      */
  323.  
  324.     if (!total_int_refl) {
  325.         Stats.RefractRays++;
  326.         hittmp.nodes = 0;
  327.         dist = FAR_AWAY;
  328.         TraceRay(&NewRay, &hittmp, EPSILON, &dist);
  329.         ShadeRay(&hittmp, &NewRay, dist, back, &newcol, contrib);
  330.         ColorMultiply(newcol, *intens, &newcol);
  331.         /*
  332.          * Attenuate transmitted color.  Note that
  333.          * if the transmitted ray hit nothing, we still
  334.          * perform this computation, as it's possible
  335.          * that 'air' has a non-unit statten.
  336.          */
  337.         statten = NewRay.media ? NewRay.media->statten :
  338.             TopMedium.statten;
  339.         if (statten != 1.0) {
  340.             statten = pow(statten, dist);
  341.             ColorScale(statten, newcol, &newcol);
  342.         }
  343.         ColorAdd(*color, newcol, color);
  344.         /* Free pushed medium */
  345.         if (enter)
  346.             free((voidstar)NewRay.media);
  347.     }
  348.  
  349.     return total_int_refl;
  350. }
  351.  
  352. static void
  353. ReflectRay(ray, pos, dir, back, intens, contrib, color)
  354. Ray *ray;
  355. Vector *pos, *dir;
  356. Color *back, *intens, *contrib, *color;
  357. {
  358.     Ray NewRay;
  359.     HitList hittmp;        /* Geom intersection record */
  360.     Color newcol;
  361.     Float dist;
  362.  
  363.     NewRay.pos = *pos;        /* Origin == hit point */
  364.     NewRay.dir = *dir;        /* Direction == reflection */
  365.     NewRay.media = ray->media;    /* Medium == old medium */
  366.     NewRay.sample = ray->sample;
  367.     NewRay.time = ray->time;
  368.     NewRay.depth = ray->depth + 1;
  369.     Stats.ReflectRays++;
  370.     hittmp.nodes = 0;
  371.     dist = FAR_AWAY;
  372.     (void)TraceRay(&NewRay, &hittmp, EPSILON, &dist);
  373.     ShadeRay(&hittmp, &NewRay, dist, back, &newcol, contrib);
  374.     ColorMultiply(newcol, *intens, &newcol);
  375.     ColorAdd(*color, newcol, color);
  376. }
  377.